package com.ruoyi.project.system.device.controller;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.*;

import com.ruoyi.framework.web.domain.R;
import com.ruoyi.project.system.device.domain.MyDevice;
import com.ruoyi.project.system.device.domain.MyDeviceDetails;
import com.ruoyi.project.system.device.domain.MyPlan;
import com.ruoyi.project.system.device.service.IMyDeviceDetailsService;
import com.ruoyi.project.system.device.service.IMyDeviceService;
import com.ruoyi.project.system.device.service.IMyPlanService;
import com.ruoyi.project.system.sample.domain.MySample;
import com.ruoyi.project.system.sample.service.IMySampleService;
import com.ruoyi.project.utils.Serial.ChuanKouListener;
import com.ruoyi.project.utils.Serial.Main;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;

import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.page.TableDataInfo;

import static com.ruoyi.project.utils.Serial.SerialPortManager.sendToPort;

/**
 * 【请填写功能名称】Controller
 * 
 * @author ruoyi
 * @date 2024-06-30
 */
@Controller
@RequestMapping("/system/details")
public class MyDeviceDetailsController extends BaseController
{
    private String prefix = "system/details";

    @Autowired
    private IMyDeviceDetailsService myDeviceDetailsService;
    @Autowired
    private IMyPlanService myPlanService;
    @Autowired
    private IMyDeviceService myDeviceService;
    @Autowired
    private IMySampleService mySampleService;
    Main main = new Main();

    @RequiresPermissions("system:details:view")
    @GetMapping()
    public String details()
    {
        return prefix + "/details";
    }

    /**
     * 查询【请填写功能名称】列表
     */
    @RequiresPermissions("system:details:list")
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(MyDeviceDetails myDeviceDetails)
    {
        startPage();
        List<MyDeviceDetails> list = myDeviceDetailsService.selectMyDeviceDetailsList(myDeviceDetails);
        return getDataTable(list);
    }

    /**
     * 导出【请填写功能名称】列表
     */
    @RequiresPermissions("system:details:export")
    @Log(title = "【设备明细导出】", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ResponseBody
    public AjaxResult export(MyDeviceDetails myDeviceDetails)
    {
        List<MyDeviceDetails> list = myDeviceDetailsService.selectMyDeviceDetailsList(myDeviceDetails);
        ExcelUtil<MyDeviceDetails> util = new ExcelUtil<MyDeviceDetails>(MyDeviceDetails.class);
        return util.exportExcel(list, "【请填写功能名称】数据");
    }

    /**
     * 新增【请填写功能名称】
     */
    @GetMapping("/add")
    public String add()
    {
        return prefix + "/add";
    }

    /**
     * 新增保存【请填写功能名称】
     */
    @RequiresPermissions("system:details:add")
    @Log(title = "【添加设备明细】", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(MyDeviceDetails myDeviceDetails)
    {
        return toAjax(myDeviceDetailsService.insertMyDeviceDetails(myDeviceDetails));
    }

    /**
     * 修改【请填写功能名称】
     */
    @RequiresPermissions("system:details:edit")
    @GetMapping("/edit/{id}")
    public String edit(@PathVariable("id") Long id, ModelMap mmap)
    {
        MyDeviceDetails myDeviceDetails = myDeviceDetailsService.selectMyDeviceDetailsById(id);
        mmap.put("myDeviceDetails", myDeviceDetails);
        return prefix + "/edit";
    }

    /**
     * 修改保存【请填写功能名称】
     */
    @RequiresPermissions("system:details:edit")
    @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(MyDeviceDetails myDeviceDetails)
    {
        return toAjax(myDeviceDetailsService.updateMyDeviceDetails(myDeviceDetails));
    }

    /**
     * 删除【请填写功能名称】
     */
    @RequiresPermissions("system:details:remove")
    @Log(title = "【请填写功能名称】", businessType = BusinessType.DELETE)
    @PostMapping( "/remove")
    @ResponseBody
    public AjaxResult remove(String ids)
    {
        return toAjax(myDeviceDetailsService.deleteMyDeviceDetailsByIds(ids));
    }
    /**
     * 查询串口数据
     */
    @PostMapping("/portDate")
    @ResponseBody
    public AjaxResult portDate()
    {
        MyDeviceDetails myDeviceDetails = new MyDeviceDetails(); // 设备详情
        try {
            String msg = ChuanKouListener.msgQueue.take();
            String[] dat = msg.split(" ");
            List<String> list = Arrays.asList(dat);
            float floatValue = 0.0f;

            if (list.get(0).equals("55")) {
                String CangTi_h1_1_now = list.get(2) + list.get(3);
                floatValue = Integer.parseInt(CangTi_h1_1_now,16) / 10;
                myDeviceDetails.setCangtiH11Now(String.valueOf(floatValue));

                String CangTi_h1_2_now = list.get(4) + list.get(5);
                floatValue = Integer.parseInt(CangTi_h1_2_now,16) / 10;
                myDeviceDetails.setCangtiH12Now(String.valueOf(floatValue));

                // 将长整型转换为double
                String hexString = list.get(9) + list.get(8) + list.get(7) + list.get(6);
                floatValue = Float.intBitsToFloat(Integer.parseInt(hexString, 16));
                myDeviceDetails.setP1Now(String.valueOf(floatValue));

                hexString = list.get(13) + list.get(12) + list.get(11) + list.get(10);
                floatValue = Float.intBitsToFloat(Integer.parseInt(hexString, 16));
                myDeviceDetails.setP2Now(String.valueOf(floatValue));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return AjaxResult.success(myDeviceDetails);
    }

    // 将十六进制字符串数组转换为字节数组
    public static byte[] hexStringsToBytes(String[] hexStrings) {
        byte[] bytes = new byte[hexStrings.length];
        for (int i = 0; i < hexStrings.length; i++) {
            bytes[i] = (byte) Integer.parseInt(hexStrings[i], 16);
        }
        return bytes;
    }
    // 将字节数组转换为float
    public static double  byteArrayToFloat(byte[] byteArray) {
        ByteBuffer buffer = ByteBuffer.wrap(byteArray);
        return buffer.getDouble();
    }
    /**
     * 启动串口数据
     */
    @PostMapping("/startPort")
    @ResponseBody
    public R startPort()
    {
        try {
            main.init();
            main.run();
        } catch (Exception e) {
            return R.fail("串口启动失败");
        }
        return R.ok();
    }

    /**
     * 启动分离模式
     */
    @PostMapping("/startSeparationMode/{planId}")
    @ResponseBody
    public R startSeparationMode(@PathVariable("planId") Long planId) throws ExecutionException, InterruptedException {
        MyPlan myPlan = myPlanService.selectMyPlanById(planId);
        //获取设定值
        MyDeviceDetails myDeviceDetails = myDeviceDetailsService.selectMyDeviceDetailsById(myPlan.getDeviceDetailsId());
        //获取设备读取到的当前温度值
        MyDevice myDevice = myDeviceService.selectMyDeviceById(myPlan.getDeviceId());
        //新增做样信息
        MySample mySample = new MySample();
        mySample.setDeviceDetailsId(myDeviceDetails.getId());
        mySample.setPlanId(planId);
        mySample.setName(myPlan.getSampleName());
        mySample.setState(0);
        mySample.setCreateBy(getLoginName());
        mySample.setCreateTime(new Date());
        mySampleService.insertMySample(mySample);
        //启动串口
        ExecutorService executor = Executors.newFixedThreadPool(4);
        Callable<String> task = () -> {
            startPort();//启动串口
            // 这里放置需要异步执行的代码
            sendPortDatePlanId(planId);//发送串口设置参数
            return "异步处理完成";
        };
        Future<String> future = executor.submit(task);

        // 在异步处理完成之前，可以继续执行其他任务
        System.out.println("执行其他任务");

        // 等待异步任务完成，并获取结果
        String result = future.get();
        System.out.println(result);

        // 关闭ExecutorService
        executor.shutdown();
        /* 3.打开真空泵，抽真空；本次抽真空用时12小时，最终达到8E-6TORR真空度；*/
        main.SendData("pupm on"); //打开真空泵
        System.out.println("打开真空泵");
        boolean isVacuumDegree = false; //判断真空度是否一致
        try {
             isVacuumDegree = ConsistencyChecker.isValidVacuumDegree(Double.parseDouble(myDevice.getP2Now())
                    ,Double.parseDouble(myDeviceDetails.getP2Seting()),1.0);
        }catch (Exception e){
            System.out.println(e);
            return R.fail("设备未连接");
        }
        if(isVacuumDegree){
            main.SendData("pupm off");
            System.out.println("关闭真空泵");
        }else {
            System.out.println("超时：真空度不一致,关闭真空泵");
            main.SendData("pupm off");
            return R.fail("真空度不一致");
        }
        System.out.println(result);
        /*4.抽真空结束后，关闭V1阀；其它三个阀维持原状；即V2关，V3开，V4关；*/
        main.SendData("v1 off");
        System.out.println("关闭V1");
        /*5.打开加热模块（temp1,temp2）对样品舱加热，同时，管路及冷阱加热（即打开temp3,temp4,temp5）,
        打开E4电磁阀，接通氮气对管路进行吹扫；选择阀S1切换至排空位*/
        main.SendData("temp1 on");
        System.out.println("打开temp1");
        main.SendData("temp2 on");
        main.SendData("temp3 on");
        main.SendData("temp4 on");
        main.SendData("temp5 on");
        main.SendData("e4 on");
        main.SendData("val1 go2");
        /*6.本次加热时间设置3小时，在加热结束前30分钟时，关闭temp3，停止富集阱加热，然后打开液氮电磁阀E2；
        对富集阱进行预冷；*/
        //打开多线程定时器
        Timer timer = new Timer();
        if (myDeviceDetails.getCangtiC2Seting() == null) {
            myDeviceDetails.setCangtiC2Seting("60");
        }
        Integer c2Time = Integer.valueOf(myDeviceDetails.getCangtiC2Seting())-30; //样品仓加热时间设定值
        Integer c3Time = Integer.valueOf(myDeviceDetails.getBujijingC3Seting()); //捕集阱富集时间设定值
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("样品仓加热到指定时间后");
                main.SendData("temp3 off"); //关闭temp3
                main.SendData("e2 on"); //打开E2
                /*
                * 加热结束后，读取T5温度值，如果T5小于负100，且能保持低于-100度
                * ，刚认为富集阱达到可富集状态，如果温度高于-80度，则认为未达到可工作状态；
                * */
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        double t5 = Double.parseDouble(myDevice.getBujijingT3Now());
                        try {
                            boolean isValidT5 = BujijinChecker.isValidT5(t5,-100,15.0);
                            /*
                            * 8.确认富集阱可工作后，关闭V3，打开V4，对样品舱吹入氮气，
                            * 当氮气吹入量达到样品舱容量后，打开V2，
                            * 此时氮气的速度要控制在较低流量（低于30ml/min）；
                            * */
                            if(isValidT5){
                                main.SendData("v3 off");
                                main.SendData("v4 on");
                                //等待吹入氮气量达到样品仓的容量
                                timer.schedule(new TimerTask() {
                                    @Override
                                    public void run() {
                                        main.SendData("v2 on");
                                        timer.schedule(new TimerTask() {
                                            @Override
                                            public void run() {
                                                /*
                                                 * 9.富集进行20分钟（时间可设置）后，关闭V2，关闭V4，E1关闭（切换到OFF状态）
                                                 * ，此时，氦气会进入到富集阱前端的三通后，再通过富集阱再达到S1选择阀，
                                                 * 此时将S1切换至进样位B；则完成了从富集阱到进GCMS的气路准备；
                                                 * */
                                                main.SendData("v2 off");
                                                main.SendData("v4 off");
                                                main.SendData("e1 off");
                                                main.SendData("val1 go1");
                                            }
                                        },20*60*1000); //等待20分钟富集
                                    }
                                },20*60*1000); //等待20分钟吹入氮气量达到样品仓的容量

                            }
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                },30*60*1000); //30分钟
            }
        },c2Time);
        main.SendData("pupm off");
        return R.ok();
    }
    public static void main(String[] args) {
        Timer timer = new Timer();
        try {
            ConsistencyChecker.isValidVacuumDegree(1
                    ,10,1.0);
        }catch (Exception e){

        }
        System.out.println("执行了");
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("2000ms后");
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        System.out.println("1000ms后");

                    }
                },1000);
            }
        },2000);


    }
    /**
     * 单独发送串口数据
     */
    @PostMapping("/sendPortDate")
    @ResponseBody
    public R sendPortDate(@PathVariable("data") String data)
    {
        try {
            main.SendData(data);
        } catch (Exception e) {
            return R.fail("发送失败,串口未连接");
        }
        return R.ok();
    }
    /**
     * 发送串口数据
     */
    @PostMapping("/sendPortDatePlanId/{planId}")
    @ResponseBody
    public R sendPortDatePlanId(@PathVariable("planId")  Long planId)
    {
        if(main == null){
            return R.fail("串口未连接");
        }
        //组装数据
        MyPlan myPlan = myPlanService.selectMyPlanById(planId);
        //获取设定值
        MyDeviceDetails myDeviceDetails = myDeviceDetailsService.selectMyDeviceDetailsById(myPlan.getDeviceDetailsId());
        int count = 0;
        byte[] dat = new byte[100];
        dat[0] = (byte) (0x55);
//        String hexString = String.format("%04X", Integer.parseInt(myDeviceDetails.getCangtiT1Seting()));
//        // 分割成高8位和低8位
//        String high8Bits = hexString.substring(0, 2); // 取前两位
//        String low8Bits = hexString.substring(2, 4); // 取后两位
        byte[] CangtiT1Seting =  myDeviceDetails.getCangtiT1Seting().getBytes(); //样品仓温度设定

        for (int i = 0; i < CangtiT1Seting.length; i++){
            dat[2+i] = CangtiT1Seting[i];
        }

        byte[] BujijingT3Seting =  myDeviceDetails.getBujijingT3Seting().getBytes();//捕集阱温度设定
        dat[2+CangtiT1Seting.length] = (byte) (99);
        for (int i = 0; i < BujijingT3Seting.length; i++){
            dat[3+CangtiT1Seting.length+i] = BujijingT3Seting[i];
        }
        byte[] BujijingT41Seting =  myDeviceDetails.getBujijingT41Seting().getBytes();//捕集阱前温度设定
        dat[3+CangtiT1Seting.length+BujijingT3Seting.length] = (byte) (99);
        for (int i = 0; i < BujijingT41Seting.length; i++){
            dat[4+CangtiT1Seting.length+BujijingT3Seting.length+i] = BujijingT41Seting[i];
        }
        byte[] BujijingT42Seting = myDeviceDetails.getBujijingT42Seting().getBytes();//捕集阱后温度设定
        dat[4+CangtiT1Seting.length+BujijingT3Seting.length+BujijingT41Seting.length] = (byte) (99);
        for (int i = 0; i < BujijingT42Seting.length; i++){
            dat[5+CangtiT1Seting.length+BujijingT3Seting.length+BujijingT41Seting.length+i] = BujijingT42Seting[i];
        }
        byte[] p1 = myDeviceDetails.getPt1Seting().getBytes();
        dat[5+CangtiT1Seting.length+BujijingT3Seting.length+BujijingT41Seting.length+BujijingT42Seting.length] = (byte) (99);
        for (int i = 0; i < p1.length; i++){
            dat[6+CangtiT1Seting.length+BujijingT3Seting.length+BujijingT41Seting.length+BujijingT42Seting.length+i] = p1[i];
        }
        byte[] p2 = myDeviceDetails.getP2Seting().getBytes();
        dat[6+CangtiT1Seting.length+BujijingT3Seting.length+BujijingT41Seting.length+BujijingT42Seting.length+p1.length] = (byte) (99);
        for (int i = 0; i < p2.length; i++){
            dat[7+CangtiT1Seting.length+BujijingT3Seting.length+BujijingT41Seting.length+BujijingT42Seting.length+p1.length+i] = p2[i];
        }
        count = CangtiT1Seting.length+BujijingT3Seting.length+BujijingT41Seting.length+BujijingT42Seting.length+p1.length+p2.length;
        dat[1] = (byte) (count);
        try {
            main.SendDat(dat);
        } catch (Exception e) {
            return R.fail("发送失败,串口未连接");
        }
        return R.ok();
    }
}
